/*******************************************************************************
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
module dwt.internal.image.fileformat;


private import dwt.dwt;



private import dwt.internal.image.giffileformat;
private import dwt.internal.image.jpegfileformat;
private import dwt.internal.image.ledatainputstream;
private import dwt.internal.image.ledataoutputstream;
private import dwt.internal.image.pngfileformat;
private import dwt.internal.image.tifffileformat;
private import dwt.internal.image.winbmpfileformat;
private import dwt.internal.image.winicofileformat;
 
private import dwt.graphics.image;
private import dwt.graphics.imagedata;
private import dwt.graphics.imageloader;

private import dwt.util.util;
private import dwt.internal.converter;

import dwt.internal.compatibility;

public abstract class FileFormat {

//	static String FORMAT_PACKAGE() { return new String("org.eclipse.dwt.internal.image");} //$NON-NLS-1$
//	static String FORMAT_SUFFIX() { return new String("FileFormat");} //$NON-NLS-1$

	static char[][] FORMATS = ["WinBMP", "WinBMP","GIF","WinICO","JPEG","PNG","TIFF"];
	LEDataInputStream inputStream;
	LEDataOutputStream outputStream;
	ImageLoader loader;
	int compression;

public static FileFormat createFileFormatFromName(char[] imagetype){
	
	char[] name = Converter.strip(imagetype);
	name = Converter.toupper(name);
	FileFormat fileformat = null;
	switch(name[]){
		case "WINBMP" :
			fileformat = new WinBMPFileFormat();
			break;
		case "WINICO" :
			fileformat = new WinICOFileFormat();
			break;
		case "GIF" :
			fileformat = new GIFFileFormat();
			break;
		case "JPEG" :
			fileformat = new JPEGFileFormat();
			break;
		case "PNG" : 
			fileformat = new PNGFileFormat();
			break;
		case "TIFF" :
			fileformat = new TIFFFileFormat();
			Util.trace(("<Shawn> : not implemented yet"));
			break;
		default:
			throw new Exception("UnKnown or unsupported image format name");
	}
	return fileformat;
}	

byte[] bitInvertData(byte[] data, int startIndex, int endIndex) {
	// Destructively bit invert data in the given ubyte array.
	for (int i = startIndex; i < endIndex; i++) {
		data[i] = cast(byte)(255 - data[i - startIndex]);
	}
	return data;
}

/**
 * Return whether or not the specified input stream
 * represents a supported file format.
 */
abstract boolean isFileFormat(LEDataInputStream stream);

abstract ImageData[] loadFromByteStream();

public ImageData[] loadFromStream(LEDataInputStream stream) {
	try {
		inputStream = stream;
		return loadFromByteStream();
	} catch (Exception e) {
		DWT.error(__FILE__, __LINE__,  e);
		return new ImageData[0];
	}
}

public static ImageData[] load(InputStream istream, ImageLoader loader) {
	ImageData[]	imgDatas;
	boolean isSupported = false;
	FileFormat fileFormat = null;
	LEDataInputStream stream = new LEDataInputStream(istream);
	for (int i = 1; i < FORMATS.length; i++) {
		if (FORMATS[i] !is null) {
			// <Shawn> need rtti support here
			try {
				fileFormat = cast(FileFormat)createFileFormatFromName(FORMATS[i]);
				if (fileFormat.isFileFormat(stream)) {
					isSupported = true;
					break;
				}
			} catch (Exception e) {
				Util.trace(e.toString());
			}
		}
	}
	if (!isSupported) {
		DWT.error(__FILE__, __LINE__, DWT.ERROR_UNSUPPORTED_FORMAT);
		return imgDatas;
	}
	fileFormat.loader = loader;
	try{
		imgDatas = fileFormat.loadFromStream(stream);
	}catch(Exception e){
		Util.trace(e.toString());
	}finally{ 
		stream.close();
	}
	return imgDatas;
}

public static void save(OutputStream os, int format, ImageLoader loader) {
	if (format < 0 || format >= FORMATS.length) DWT.error(__FILE__, __LINE__, DWT.ERROR_INVALID_ARGUMENT);
	if (FORMATS[format] is null) DWT.error(__FILE__, __LINE__, DWT.ERROR_INVALID_ARGUMENT);

	/* We do not currently support writing multi-image files,
	 * so we use the first image data in the loader's array. */
	ImageData data = loader.data[0];
	LEDataOutputStream stream = new LEDataOutputStream(os);
	FileFormat fileFormat = null;
	try {
//		Class clazz = Class.forName(FORMAT_PACKAGE + '.' + FORMATS[format] + FORMAT_SUFFIX);
//		fileFormat = cast(FileFormat)clazz.newInstance();
		fileFormat = createFileFormatFromName(FORMATS[format]);
	} catch (Exception e) {
		DWT.error(__FILE__, __LINE__, DWT.ERROR_INVALID_ARGUMENT);
	}
	if (format == DWT.IMAGE_BMP_RLE) {
		switch (data.depth) {
			case 8: fileFormat.compression = 1; break;
			case 4: fileFormat.compression = 2; break;
			default : break;
		}
	}
	fileFormat.unloadIntoStream(data, stream);
}

abstract void unloadIntoByteStream(ImageData image);

public void unloadIntoStream(ImageData image, LEDataOutputStream stream) {
	try {
		outputStream = stream;
		unloadIntoByteStream(image);
		outputStream.close();
	} catch (Exception e) {
		try {
			outputStream.close();
		}catch(Exception f)
		{}
		DWT.error(__FILE__, __LINE__,  e);
	}
}
}
